/******************************************************************************
秋夜静，独坐对残灯。
啼笑非非谁识我，坐行梦梦尽缘君，何所慰消沉。
风卷雨，雨复卷侬心。
心似欲随风雨去，茫茫大海任浮沉。
无爱亦无恨。
******************************************************************************/
#include "kbRGB_Int.h"
#include <math.h>
#include "kbRGB_Int_Effect.h"

#define RGBGetRValue(rgb)   (rgb & 0x000000FF)
#define RGBGetGValue(rgb)   ((rgb >> 8) & 0x000000FF)
#define RGBGetBValue(rgb)   ((rgb >> 16) & 0x000000FF)

#define ToRGBColor(r, g, b) ((uint32_t)((b << 16) | (g << 8) | (r)))
static unsigned char ScreenChanel(unsigned char a, unsigned char b)
{
    return 255 - ((255 - b) * (255 - a) >> 8);;
}
static uint32_t Screen(uint32_t color1, uint32_t color2)
{
    return ToRGBColor(
                ScreenChanel(RGBGetRValue(color1), RGBGetRValue(color2)),
                ScreenChanel(RGBGetGValue(color1), RGBGetGValue(color2)),
                ScreenChanel(RGBGetBValue(color1), RGBGetBValue(color2))
                );
};
static unsigned char InterpolateChanel(unsigned char a, unsigned char b, float x)
{
    return (int) ((b - a) * x + a);
}
static uint32_t Interpolate(uint32_t color1, uint32_t color2, float fraction)
{
    return ToRGBColor(
                InterpolateChanel(RGBGetRValue(color1), RGBGetRValue(color2), fraction),
                InterpolateChanel(RGBGetGValue(color1), RGBGetGValue(color2), fraction),
                InterpolateChanel(RGBGetBValue(color1), RGBGetBValue(color2), fraction)
                );
}

/*************************************************************************************************\
|        Beams [9]                                                                                |
\*************************************************************************************************/
void kbRGB_Int_CrossingBeams_Init(struct kbRGB_Int_Params *const params)    // 交叉梁   // Fail
{
    params->Speed = 10;
    params->Slider2Val = 30;
    params->Beams.v_speed = 20;
    params->Beams.h_speed = 10;
    params->Beams.glow = 30;
    params->Beams.thickness = 2;
    //CrossingBeams_SetRandomColorsEnabled(1);
    //SetRandomColors(&params->Beams);
    params->Beams.hsv_hue1 = 0<<4;
    params->Beams.hsv_hue2 = 180<<4;
}
static uint32_t CrossingBeams_GetColor(int16_t dx, int16_t dy,  uint16_t w, const uint16_t h/*, const int16_t x_progress, const int16_t y_progress*/, const uint16_t hsv_hue1, const uint16_t hsv_hue2)
{

//    float x_progress = 0.5 * (1 + sine_x) * w;
//    float y_progress = 0.5 * (1 + sine_y) * h;
//    float x_progress = 0.5 * (kbRGB_SinMax + sine_x) * w/kbRGB_SinMax;
//    float y_progress = 0.5 * (kbRGB_SinMax + sine_y) * h/kbRGB_SinMax;
    //int16_t x_progress = ((255 + sine_x) * w)>>(KBRGB_SIN_CAL_PRE+1);
    //int16_t y_progress = ((255 + sine_y) * h)>>(KBRGB_SIN_CAL_PRE+1);

    //float distance_x = fabs(x_progress/(float)kbRGB_SinMax - x);
    float distance_x = abs(dx)/(float)kbRGB_SinMax;
    //float distance_x_percent = std::min<float>(1,pow(distance_x / w,
    //                                                 distance_x > thickness ? 0.01 * glow : 1));
    //float distance_x_percent = pow(distance_x / w, distance_x > params->Beams.thickness ? 0.01 * params->Beams.glow : 1);
    //float distance_x_percent = pow(distance_x / w, distance_x > params->Beams.thickness ? 0.01 * params->Beams.glow : 1);
    float distance_x_percent = (distance_x / w)*4;
    if(distance_x_percent>1) distance_x_percent=1;

    //float distance_y = fabs(y_progress/(float)kbRGB_SinMax - y);
    float distance_y = abs(dy)/(float)kbRGB_SinMax;
    //float distance_y_percent = std::min<float>(1, pow(distance_y / h,
    //                                                  distance_y > thickness ? 0.01 * glow : 1));
    //float distance_y_percent = pow(distance_y / h, distance_y > params->Beams.thickness ? 0.01 * params->Beams.glow : 1);
    float distance_y_percent = (distance_y / h)*6;
    if(distance_y_percent>1) distance_y_percent=1;

    hsv_t hsv_tmp;

    hsv_tmp.value = 255 * (1 - distance_x_percent);
    hsv_tmp.hue = hsv_hue1;
    hsv_tmp.saturation = 255;//hsv1->saturation;

    uint32_t color1 = (hsv2rgb(&hsv_tmp));

    hsv_tmp.value = 255 * (1 - distance_y_percent);
    hsv_tmp.hue = hsv_hue2;//hsv2->hue;
    hsv_tmp.saturation = 255;//hsv2->saturation;

    uint32_t color2 = (hsv2rgb(&hsv_tmp));

    return Screen(color1,color2);
}
void kbRGB_Int_CrossingBeams(const uint16_t cols, const uint16_t rows, const uint8_t speed, const int reverse, struct kbRGB_Int_Params *const params)    // 交叉梁   // Fail
{
//    double sine_x = sin( 0.01 * kbrgb_Params.Beams.h_speed * kbRGB_progress);
//    double sine_y = sin( 0.01 * kbrgb_Params.Beams.v_speed * kbRGB_progress);
//    int16_t sine_x = kbRGB_Sin( (params->Beams.h_speed * progress)*1.80/KBRGB_PI);
//    int16_t sine_y = kbRGB_Sin( (params->Beams.v_speed * progress)*1.80/KBRGB_PI);
    const int32_t anglex = ((int)(params->Beams.h_speed * params->progress*(1.80/KBRGB_PI)) )>>(KB_RGB_PARAM_PRE-KBRGB_COS_PRE);
    const int32_t angley = ((int)(params->Beams.v_speed * params->progress*(1.80/KBRGB_PI)) )>>(KB_RGB_PARAM_PRE-KBRGB_COS_PRE);
    int16_t sine_x = kbRGB_Sin_Int(anglex);
    int16_t sine_y = kbRGB_Sin_Int(angley);
    //    float x_progress = 0.5 * (kbRGB_SinMax + sine_x) * w/kbRGB_SinMax;
    //    float y_progress = 0.5 * (kbRGB_SinMax + sine_y) * h/kbRGB_SinMax;
    int16_t x_progress = ((kbRGB_SinMax + sine_x) * cols)>>1;///kbRGB_SinMax;
    int16_t y_progress = ((kbRGB_SinMax + sine_y) * rows)>>1;///kbRGB_SinMax;
    for (uint16_t col_id = 0; col_id < cols; col_id++)
    {
        for (uint16_t row_id = 0; row_id < rows; row_id++)
        {
            uint32_t color = CrossingBeams_GetColor(x_progress-(col_id<<8), y_progress-(row_id<<8), cols, rows/*, x_progress, y_progress*/, params->Beams.hsv_hue1>>4, params->Beams.hsv_hue2>>4);
            kbRGB_pset(col_id, row_id, color);
        }
    }
    //progress += (float) Speed / (float) FPS;
    params->progress +=  ((params->Speed+speed*5)<<KB_RGB_PARAM_PRE) / params->FPS;

    //params->Beams.hsv1.hue++;
    //params->Beams.hsv2.hue++;
    params->Beams.hsv_hue1+=8;
    params->Beams.hsv_hue2+=8;
}

/*************************************************************************************************\
|        RotatingBeam [9]                                                                              |
\*************************************************************************************************/
struct LineInt{
    struct{
        int32_t x,y;
    }p1,p2;
    int32_t _sqrt;
};
enum RotatingBeamMode
{
    CLOCKWISE = 0,
    COUNTER_CLOCKWISE = 1,
    PENDULUM = 2,
    WIPERS = 3,
    SWING_H = 4,
    SWING_V = 5
};

void kbRGB_Int_RotatingBeam_Init(struct kbRGB_Int_Params *const params)    // 旋转射束
{
    params->Speed = 50;
    params->Slider2Val = 10;
    params->Beams.thickness = 0;
    params->Beams.v_speed = 10;
    params->Beams.h_speed = 15;
    params->Beams.glow = 30;
    params->Beams.thickness = 1;
    params->Beams.RotatingMode = CLOCKWISE;//CLOCKWISE;
    //SetRandomColors(&params->Beams);
    params->Beams.hsv_hue1 = 0<<4;
    params->Beams.hsv_hue2 = 180<<4;
}
static void RotatingBeamRemodel_Rotate(struct LineInt* const line, const int32_t angle, const int RotatingMode)
{
    //const int32_t angle = kbRGB_progress*180.0f/KBRGB_PI;
    switch (RotatingMode)
    {
    case CLOCKWISE:
    {
        int16_t x = (kbRGB_SinMax + kbRGB_Cos_Int(angle))>>1;
        int16_t y = (kbRGB_SinMax + kbRGB_Sin_Int(angle))>>1;
        line->p1.x=(x);
        line->p1.y=(y);
        line->p2.x=(kbRGB_SinMax - x);
        line->p2.y=(kbRGB_SinMax - y);
        break;
    }
    case COUNTER_CLOCKWISE:
    {
        int16_t x = (kbRGB_SinMax + kbRGB_Cos_Int(-angle))>>1;
        int16_t y = (kbRGB_SinMax + kbRGB_Sin_Int(-angle))>>1;
        line->p1.x=(x);
        line->p1.y=(y);
        line->p2.x=(kbRGB_SinMax - x);
        line->p2.y=(kbRGB_SinMax - y);
        break;
    }
    case PENDULUM:
    {
        int16_t x = (kbRGB_SinMax + kbRGB_Cos_Int(angle))>>1;
        line->p1.x=(kbRGB_SinMax>>1)+1;
        line->p1.y=(0);
        line->p2.x=(x);
        line->p2.y=(kbRGB_SinMax);
        break;
    }
    case WIPERS:
    {
        int16_t x = (kbRGB_SinMax + kbRGB_Cos_Int(angle))>>1;
        line->p1.x=(x);
        line->p1.y=(0);
        line->p2.x=(kbRGB_SinMax>>1)+1;
        line->p2.y=(kbRGB_SinMax);
        break;
    }
    case SWING_H:
    {
        int16_t x = (kbRGB_SinMax + kbRGB_Cos_Int(angle))>>1;
        line->p1.x=(0);
        line->p1.y=(x);
        line->p2.x=(kbRGB_SinMax);
        line->p2.y=(kbRGB_SinMax - x);
        break;
    }
    case SWING_V:
    {
        int16_t x = (kbRGB_SinMax + kbRGB_Cos_Int(angle))>>1;
        line->p1.x=(x);
        line->p1.y=(0);
        line->p2.x=(kbRGB_SinMax - x);
        line->p2.y=(kbRGB_SinMax);
        break;
    }
    default:
        line->p1.x=0;
        line->p1.y=0;
        line->p2.x=kbRGB_SinMax;
        line->p2.y=kbRGB_SinMax;
    }
}
static uint32_t RotatingBeamRemodel_GetColor(const uint16_t x0, const uint16_t y0, struct LineInt* const l, const uint16_t w, const uint16_t h, const uint16_t hsv_hue1, const uint32_t color2)
{
    const int32_t x1 = l->p1.x;///(float)kbRGB_SinMax;
    const int32_t x2 = l->p2.x;///(float)kbRGB_SinMax;
    const int32_t y1 = l->p1.y;///(float)kbRGB_SinMax;
    const int32_t y2 = l->p2.y;///(float)kbRGB_SinMax;

    //float distance = fabs((x2 - x1) * (y1 - y0) - (x1 - x0) * (y2 - y1)) / sqrt(pow(x2 - x1 ,2) + pow(y2 - y1,2));
    //float distance = fabs((x2 - x1) * (y1 - y0) - (x1 - x0) * (y2 - y1)) / (l->_sqrt/(float)(kbRGB_SinMax));
    //float distance = fabs((x2 - x1) * (y1 - y0) - (x1 - x0) * (y2 - y1)) / (l->_sqrt/(float)(kbRGB_SinMax));
    //float distance = fabs(((x2 - x1) ) * ((y1 - y0) ) - ((x1 - x0) ) * ((y2 - y1) ))/(float)(kbRGB_SinMax*kbRGB_SinMax) / (l->_sqrt/(float)(kbRGB_SinMax));
    //float distance = fabs(((x2 - x1) ) * ((y1 - y0) ) - ((x1 - x0) ) * ((y2 - y1) ))/(float)(kbRGB_SinMax) / (l->_sqrt);
    int32_t _distance = ((x2 - x1) ) * ((y1 - y0) ) - ((x1 - x0) ) * ((y2 - y1) ); if(_distance<0) _distance=-_distance;
    float distance = _distance/(float)(kbRGB_SinMax*l->_sqrt);

    hsv_t hsv_tmp;
    //int mi = _distance < ((kbrgb_Params.Beams.thickness<<8)*l->_sqrt) ? 1 : kbrgb_Params.Beams.glow;

    //hsv_tmp.value = kbrgb_Params.Beams.hsv1.value - kbrgb_Params.Beams.hsv1.value * pow(distance / (0.5*(w+h)) , distance < kbrgb_Params.Beams.thickness ? 1 : kbrgb_Params.Beams.glow);
    //hsv_tmp.value = kbrgb_Params.Beams.hsv1.value - kbrgb_Params.Beams.hsv1.value * pow(distance / (0.5*(w+h)) , mi);
    //hsv_tmp.value = kbrgb_Params.Beams.hsv1.value - kbrgb_Params.Beams.hsv1.value * (distance / ((w+h)>>1));
    //hsv_tmp.value = params->Beams.hsv1.value - ((params->Beams.hsv1.value * ((_distance) / (((w+h)>>1)*l->_sqrt)))>>8 );
    hsv_tmp.value = 255 - ((255 * ((_distance) / (((w+h)>>1)*l->_sqrt)))>>8 );
    hsv_tmp.hue = hsv_hue1;//params->Beams.hsv1.hue;
    //hsv_tmp.hue = ((hsv_hue1 * ((_distance) / (((w+h)>>1)*l->_sqrt)))>>8 )%360;//params->Beams.hsv1.hue;
    //hsv_tmp.hue = (hsv_hue1+((360 * ((_distance) / (((w+h)>>1)*l->_sqrt)))>>8 ))%360;//params->Beams.hsv1.hue;
    hsv_tmp.saturation = 255;//params->Beams.hsv1.saturation;

    uint32_t color1 = (hsv2rgb(&hsv_tmp));

    //uint32_t color2 = (hsv2rgb(&params->Beams.hsv2));

    return Interpolate(color2, color1, 1 - distance / (0.5*(w+h)) );
}
void kbRGB_Int_RotatingBeam(const uint16_t cols, const uint16_t rows, const uint8_t speed, const int reverse, struct kbRGB_Int_Params *const params)    // 旋转射束
{
    //const int32_t angle = (1<<KBRGB_COS_PRE)*progress*180.0f/KBRGB_PI/2560;
    //const int32_t angle = ((1<<KBRGB_COS_PRE)*progress*18/(int)KBRGB_PI)>>8;
    const int32_t angle = (params->progress*18/(int)KBRGB_PI)>>(KB_RGB_PARAM_PRE-KBRGB_COS_PRE);
    struct LineInt lineInt; RotatingBeamRemodel_Rotate(&lineInt, angle, params->Beams.RotatingMode);
    struct LineInt line; //RotatingBeamRemodel_Rotate(&line);
    const uint16_t width = cols;
    const uint16_t height = rows;
    hsv_t hsv2;
    hsv2.hue = params->Beams.hsv_hue2;
    hsv2.saturation = 255;
    hsv2.value = 255;
    uint32_t color2 = (hsv2rgb(&hsv2));
    lineInt.p1.x = lineInt.p1.x * width;
    lineInt.p2.x = lineInt.p2.x * width;
    lineInt.p1.y = lineInt.p1.y * height;
    lineInt.p2.y = lineInt.p2.y * height;
    line.p1.x = lineInt.p1.x;///(float)kbRGB_SinMax;
    line.p2.x = lineInt.p2.x;///(float)kbRGB_SinMax;
    line.p1.y = lineInt.p1.y;///(float)kbRGB_SinMax;
    line.p2.y = lineInt.p2.y;///(float)kbRGB_SinMax;
    line.p2.x = line.p2.x - line.p1.x;
    line.p2.y = line.p2.y - line.p1.y;
    //loat distance = fabs((x2 - x1) * (y1 - y0) - (x1 - x0) * (y2 - y1)) / sqrt(pow(x2 - x1 ,2) + pow(y2 - y1,2));
    //lineInt._sqrt = sqrt(pow(line.p2.x - line.p1.x ,2) + pow(line.p2.y - line.p1.y,2));
    //lineInt._sqrt = sqrt(pow(line.p2.x,2) + pow(line.p2.y,2));
    //lineInt._sqrt = sqrt(line.p2.x*line.p2.x/(float)(kbRGB_SinMax*kbRGB_SinMax) + line.p2.y*line.p2.y/(float)(kbRGB_SinMax*kbRGB_SinMax));
    lineInt._sqrt = sqrt(line.p2.x*line.p2.x + line.p2.y*line.p2.y);///(float)(kbRGB_SinMax);
    for(uint16_t row_id = 0; row_id < height; row_id++)
    {
        for(uint16_t col_id = 0; col_id <  width; col_id++)
        {
            uint32_t color = RotatingBeamRemodel_GetColor(col_id<<8, row_id<<8, &lineInt, width - 1, height - 1, params->Beams.hsv_hue1, color2);
            kbRGB_pset(col_id, row_id, color);
        }
    }
    //progress +=  256* Speed / FPS;
    params->progress +=  ((params->Speed+speed*10)<<KB_RGB_PARAM_PRE) / params->FPS;

//    params->Beams.hsv1.hue++;
//    params->Beams.hsv2.hue++;
    params->Beams.hsv_hue1++;
    params->Beams.hsv_hue2++;
}
